/*****************************************************************************/
/**
 *  @file   Widget.h
 *  @author Naohisa Sakamoto
 */
/*----------------------------------------------------------------------------
 *
 *  Copyright (c) Visualization Laboratory, Kyoto University.
 *  All rights reserved.
 *  See http://www.viz.media.kyoto-u.ac.jp/kvs/copyright/ for details.
 *
 *  $Id$
 */
/*****************************************************************************/
#ifndef WIDGET_H_INCLUDE
#define WIDGET_H_INCLUDE

#include <kvs/Bounds>
#include <kvs/glut/Screen>
#include <kvs/glut/PushButton>
#include <kvs/glut/RadioButton>
#include <kvs/glut/RadioButtonGroup>
#include <kvs/glut/CheckBox>
#include <kvs/glut/Slider>
#include <kvs/glut/LegendBar>
#include <kvs/glut/OrientationAxis>
#include "Parameter.h"
#include "Command.h"


namespace Widget
{

class PolygonOpacitySlider : public kvs::glut::Slider
{
    Parameter& m_parameter;

public:

    PolygonOpacitySlider( kvs::glut::Screen* screen, Parameter& parameter ):
        kvs::glut::Slider( screen ),
        m_parameter( parameter ) {};

    void sliderMoved( void ) { Command::SetPolygonOpacity( m_parameter, value() ); }
};

class PointCheckBox : public kvs::glut::CheckBox
{
    Parameter& m_parameter;

public:

    PointCheckBox( kvs::glut::Screen* screen, Parameter& parameter ):
        kvs::glut::CheckBox( screen ),
        m_parameter( parameter ) {};

    void stateChanged( void )
    {
        if ( state() ) Command::ShowPoint( m_parameter );
        else Command::HidePoint( m_parameter );
    }
};

class BoundsCheckBox : public kvs::glut::CheckBox
{
    Parameter& m_parameter;

public:

    BoundsCheckBox( kvs::glut::Screen* screen, Parameter& parameter ):
        kvs::glut::CheckBox( screen ),
        m_parameter( parameter ) {};

    void stateChanged( void )
    {
        if ( state() ) Command::ShowBounds( m_parameter, m_parameter.point );
        else Command::HideBounds( m_parameter );
    }
};

class XScaleSlider : public kvs::glut::Slider
{
    Parameter& m_parameter;

public:

    XScaleSlider( kvs::glut::Screen* screen, Parameter& parameter ):
        kvs::glut::Slider( screen ),
        m_parameter( parameter ) {};

    void sliderMoved( void )
    {
        kvs::Real32 center = 0.5f * ( m_parameter.xmax + m_parameter.xmin );
        kvs::Real32 diff = m_parameter.tensor->maxObjectCoord().x() - m_parameter.tensor->minObjectCoord().x();
        diff *= value() * 0.5f;

        m_parameter.xmin = center - diff;
        m_parameter.xmax = center + diff;
        m_parameter.point->setXMin( m_parameter.xmin );
        m_parameter.point->setXMax( m_parameter.xmax );
        m_parameter.point->reset_coordinates( kvs::RGBColor( 255, 100, 100 ) );
        m_parameter.point->updateMinMaxCoords();
        m_parameter.compositor->changeObject( m_parameter.point, m_parameter.point, false );

        kvs::LineObject* bounds = new kvs::Bounds( m_parameter.point );
        bounds->setColor( kvs::RGBColor( 255, 100, 100 ) );
        m_parameter.compositor->changeObject( m_parameter.bounds, bounds, true );
        m_parameter.bounds = bounds;
    }
};

class YScaleSlider : public kvs::glut::Slider
{
    Parameter& m_parameter;

public:

    YScaleSlider( kvs::glut::Screen* screen, Parameter& parameter ):
        kvs::glut::Slider( screen ),
        m_parameter( parameter ) {};

    void sliderMoved( void )
    {
        kvs::Real32 center = 0.5f * ( m_parameter.ymax + m_parameter.ymin );
        kvs::Real32 diff = m_parameter.tensor->maxObjectCoord().y() - m_parameter.tensor->minObjectCoord().y();
        diff *= value() * 0.5f;

        m_parameter.ymin = center - diff;
        m_parameter.ymax = center + diff;
        m_parameter.point->setYMin( m_parameter.ymin );
        m_parameter.point->setYMax( m_parameter.ymax );
        m_parameter.point->reset_coordinates( kvs::RGBColor( 255, 100, 100 ) );
        m_parameter.point->updateMinMaxCoords();
        m_parameter.compositor->changeObject( m_parameter.point, m_parameter.point, false );

        kvs::LineObject* bounds = new kvs::Bounds( m_parameter.point );
        bounds->setColor( kvs::RGBColor( 255, 100, 100 ) );
        m_parameter.compositor->changeObject( m_parameter.bounds, bounds, true );
        m_parameter.bounds = bounds;
    }
};

class ZScaleSlider : public kvs::glut::Slider
{
    Parameter& m_parameter;

public:

    ZScaleSlider( kvs::glut::Screen* screen, Parameter& parameter ):
        kvs::glut::Slider( screen ),
        m_parameter( parameter ) {};

    void sliderMoved( void )
    {
        kvs::Real32 center = 0.5f * ( m_parameter.zmax + m_parameter.zmin );
        kvs::Real32 diff = m_parameter.tensor->maxObjectCoord().z() - m_parameter.tensor->minObjectCoord().z();
        diff *= value() * 0.5f;

        m_parameter.zmin = center - diff;
        m_parameter.zmax = center + diff;
        m_parameter.point->setZMin( m_parameter.zmin );
        m_parameter.point->setZMax( m_parameter.zmax );
        m_parameter.point->reset_coordinates( kvs::RGBColor( 255, 100, 100 ) );
        m_parameter.point->updateMinMaxCoords();
        m_parameter.compositor->changeObject( m_parameter.point, m_parameter.point, false );

        kvs::LineObject* bounds = new kvs::Bounds( m_parameter.point );
        bounds->setColor( kvs::RGBColor( 255, 100, 100 ) );
        m_parameter.compositor->changeObject( m_parameter.bounds, bounds, true );
        m_parameter.bounds = bounds;
    }
};

class XTranslateSlider : public kvs::glut::Slider
{
    Parameter& m_parameter;

public:

    XTranslateSlider( kvs::glut::Screen* screen, Parameter& parameter ):
        kvs::glut::Slider( screen ),
        m_parameter( parameter ) {};

    void sliderMoved( void )
    {
        kvs::Real32 center = m_parameter.tensor->maxObjectCoord().x() - m_parameter.tensor->minObjectCoord().x();
        center *= value() * 0.5f;
        center += m_parameter.center.x();

        kvs::Real32 diff = m_parameter.xmax - m_parameter.xmin;
        diff *= 0.5f;

        m_parameter.xmin = center - diff;
        m_parameter.xmax = center + diff;
        m_parameter.point->setXMin( m_parameter.xmin );
        m_parameter.point->setXMax( m_parameter.xmax );
        m_parameter.point->reset_coordinates( kvs::RGBColor( 255, 100, 100 ) );
        m_parameter.point->updateMinMaxCoords();
        m_parameter.compositor->changeObject( m_parameter.point, m_parameter.point, false );

        kvs::LineObject* bounds = new kvs::Bounds( m_parameter.point );
        bounds->setColor( kvs::RGBColor( 255, 100, 100 ) );
        m_parameter.compositor->changeObject( m_parameter.bounds, bounds, true );
        m_parameter.bounds = bounds;
    }
};

class YTranslateSlider : public kvs::glut::Slider
{
    Parameter& m_parameter;

public:

    YTranslateSlider( kvs::glut::Screen* screen, Parameter& parameter ):
        kvs::glut::Slider( screen ),
        m_parameter( parameter ) {};

    void sliderMoved( void )
    {
        kvs::Real32 center = m_parameter.tensor->maxObjectCoord().y() - m_parameter.tensor->minObjectCoord().y();
        center *= value() * 0.5f;
        center += m_parameter.center.y();

        kvs::Real32 diff = m_parameter.ymax - m_parameter.ymin;
        diff *= 0.5f;

        m_parameter.ymin = center - diff;
        m_parameter.ymax = center + diff;
        m_parameter.point->setYMin( m_parameter.ymin );
        m_parameter.point->setYMax( m_parameter.ymax );
        m_parameter.point->reset_coordinates( kvs::RGBColor( 255, 100, 100 ) );
        m_parameter.point->updateMinMaxCoords();
        m_parameter.compositor->changeObject( m_parameter.point, m_parameter.point, false );

        kvs::LineObject* bounds = new kvs::Bounds( m_parameter.point );
        bounds->setColor( kvs::RGBColor( 255, 100, 100 ) );
        m_parameter.compositor->changeObject( m_parameter.bounds, bounds, true );
        m_parameter.bounds = bounds;
    }
};

class ZTranslateSlider : public kvs::glut::Slider
{
    Parameter& m_parameter;

public:

    ZTranslateSlider( kvs::glut::Screen* screen, Parameter& parameter ):
        kvs::glut::Slider( screen ),
        m_parameter( parameter ) {};

    void sliderMoved( void )
    {
        kvs::Real32 center = m_parameter.tensor->maxObjectCoord().z() - m_parameter.tensor->minObjectCoord().z();
        center *= value() * 0.5f;
        center += m_parameter.center.z();

        kvs::Real32 diff = m_parameter.zmax - m_parameter.zmin;
        diff *= 0.5f;

        m_parameter.zmin = center - diff;
        m_parameter.zmax = center + diff;
        m_parameter.point->setZMin( m_parameter.zmin );
        m_parameter.point->setZMax( m_parameter.zmax );
        m_parameter.point->reset_coordinates( kvs::RGBColor( 255, 100, 100 ) );
        m_parameter.point->updateMinMaxCoords();
        m_parameter.compositor->changeObject( m_parameter.point, m_parameter.point, false );

        kvs::LineObject* bounds = new kvs::Bounds( m_parameter.point );
        bounds->setColor( kvs::RGBColor( 255, 100, 100 ) );
        m_parameter.compositor->changeObject( m_parameter.bounds, bounds, true );
        m_parameter.bounds = bounds;
    }
};

class XResolutionSlider : public kvs::glut::Slider
{
    Parameter& m_parameter;

public:

    XResolutionSlider( kvs::glut::Screen* screen, Parameter& parameter ):
        kvs::glut::Slider( screen ),
        m_parameter( parameter ) {};

    void sliderMoved( void )
    {
        m_parameter.point->setResX( value() );
        m_parameter.point->reset_coordinates( kvs::RGBColor( 255, 100, 100 ) );
        m_parameter.point->updateMinMaxCoords();
        m_parameter.compositor->changeObject( m_parameter.point, m_parameter.point, false );
    }
};

class YResolutionSlider : public kvs::glut::Slider
{
    Parameter& m_parameter;

public:

    YResolutionSlider( kvs::glut::Screen* screen, Parameter& parameter ):
        kvs::glut::Slider( screen ),
        m_parameter( parameter ) {};

    void sliderMoved( void )
    {
        m_parameter.point->setResY( value() );
        m_parameter.point->reset_coordinates( kvs::RGBColor( 255, 100, 100 ) );
        m_parameter.point->updateMinMaxCoords();
        m_parameter.compositor->changeObject( m_parameter.point, m_parameter.point, false );
    }
};

class ZResolutionSlider : public kvs::glut::Slider
{
    Parameter& m_parameter;

public:

    ZResolutionSlider( kvs::glut::Screen* screen, Parameter& parameter ):
        kvs::glut::Slider( screen ),
        m_parameter( parameter ) {};

    void sliderMoved( void )
    {
        m_parameter.point->setResZ( value() );
        m_parameter.point->reset_coordinates( kvs::RGBColor( 255, 100, 100 ) );
        m_parameter.point->updateMinMaxCoords();
        m_parameter.compositor->changeObject( m_parameter.point, m_parameter.point, false );
    }
};

class MajorPrincipalButton : public kvs::glut::RadioButton
{
    Parameter& m_parameter;

public:

    MajorPrincipalButton( kvs::glut::Screen* screen, Parameter& parameter ):
        kvs::glut::RadioButton( screen ),
        m_parameter( parameter ) {};

    void stateChanged( void ) { if ( state() ) m_parameter.line_direction = 0; }
};

class IntermediatePrincipalButton : public kvs::glut::RadioButton
{
    Parameter& m_parameter;

public:

    IntermediatePrincipalButton( kvs::glut::Screen* screen, Parameter& parameter ):
        kvs::glut::RadioButton( screen ),
        m_parameter( parameter ) {};

    void stateChanged( void ) { if ( state() ) m_parameter.line_direction = 1; }
};

class MinorPrincipalButton : public kvs::glut::RadioButton
{
    Parameter& m_parameter;

public:

    MinorPrincipalButton( kvs::glut::Screen* screen, Parameter& parameter ):
        kvs::glut::RadioButton( screen ),
        m_parameter( parameter ) {};

    void stateChanged( void ) { if ( state() ) m_parameter.line_direction = 2; }
};

class ExtractButton : public kvs::glut::PushButton
{
    Parameter& m_parameter;

public:

    ExtractButton( kvs::glut::Screen* screen, Parameter& parameter ):
        kvs::glut::PushButton( screen ),
        m_parameter( parameter ) {};

    void released( void ) { Command::ExtractLine( m_parameter ); }
};

class ClearButton : public kvs::glut::PushButton
{
    Parameter& m_parameter;

public:

    ClearButton( kvs::glut::Screen* screen, Parameter& parameter ):
        kvs::glut::PushButton( screen ),
        m_parameter( parameter ) {};

    void released( void ) { Command::ClearLine( m_parameter ); }
};

class OrientationAxis : public kvs::glut::OrientationAxis
{
public:

    OrientationAxis( kvs::ScreenBase* screen ): kvs::glut::OrientationAxis( screen ) {};
    void screenResized( void ){ setX( screen()->width() - width() ); }
};

class LegendBar : public kvs::glut::LegendBar
{
public:

    LegendBar( kvs::ScreenBase* screen ): kvs::glut::LegendBar( screen ) {};
    void screenResized( void )
    {
        setX( screen()->width() - width() );
        setY( screen()->height() - height() );
    }
};

} // end of namespace Widget

#endif // WIDGET_H_INCLUDE
